/**
 * DS18B20介绍
 * DS18B20是一种常见的"数字温度传感器"，其控制命令和数据都是以数字信号的方式输入输出，
 * 相比较于"模拟温度传感器"(热敏电阻)，具有功能强大、硬件简单、易扩展、抗干扰性强等特点
 * 测温范围：-55°C 到 +125°C, 最高分辨率: 0.0625°C
 * 通信接口：1-Wire（单总线）
 * 其它特征：可形成总线结构、内置温度报警功能、可寄生供电(数据线+GND, 不要VCC)
 * 
 * 引脚     功能
 *  VDD     电源（3.0V ~ 5.5V）
 *  GND     电源地
 *   DQ     单总线接口
 * 
 * 内部结构框图:
 * 64-BIT ROM：作为器件地址，用于总线通信的寻址
 * SCRATCHPAD（暂存器）：用于总线的数据交互
 * EEPROM：用于保存温度触发阈值和配置参数
 * 
 * 存储器结构:
 *          SCRATCHPAD(POWER-UP STATE)(scratchpad /'skrætʃpæd/暂存器)
 * Byte 0   Temperature LSB (50h)
 * Byte 1   Temperature MSB (05h)                                           EEPROM
 * Byte 2   TH Register or User Byte 1* <-----------------------------> TH Register or User Byte 1
 * Byte 3   TL Register or User Byte 2* <-----------------------------> TL Register or User Byte 2
 * Byte 4   Configuration Register*     <-----------------------------> Configuration Register
 * Byte 5   Reserved (FFh)
 * Byte 6   Reserved
 * Byte 7   Reserved (10h)
 * Byte 8   CRC*
 * *Power-up state depends on valels) stored in EEPROM
 * 
 * DS18B20操作流程:
 * 初始化：从机复位，主机判断从机是否响应
 * ROM操作：ROM指令+本指令需要的读写操作
 * 功能操作：功能指令+本指令需要的读写操作
 * 
 * ROM指令
 * SEARCH ROM [F0h]     搜寻ROM (F0), 操作较复杂
 * READ ROM [33h]       读ROM (从ROM读数据)
 * MATCH ROM [55h]      匹配ROM (根据ROM地址, 匹配某1个设备)
 * SKIP ROM [CCh]       跳过ROM (线上只有1个从机, 可不用发地址, 直接跳过)
 * ALARM SEARCH [ECh]   报警搜索 (找哪一个设备在报警), 操作较复杂
 * 
 * 功能指令
 * CONVERT T [44h]          从机启动"温度传感器", 将数值放入"暂存器"
 * WRITE SCRATCHPAD [4Eh]   将写入的数据 发送到"暂存器"的 Byte2~4
 * READ SCRATCHPAD [BEh]    从"暂存器"读取温度时
 * COPY SCRATCHPAD [48h]    复制暂存器: 将暂存器里的值写入到EEPROM
 * RECALL E2 [B8h]          将 EEPROM 中的值复制到"暂存器"
 * READ POWER SUPPLY [B4h]  读取设备供电模式: 寄生/独立供电
 * 
 */
#include "_1Wire_Bus_Utils.h"

//ROM指令: 跳过ROM
static code unsigned char DS18B20_SKIP_ROM = 0xCC;
//功能指令: 从机启动"温度传感器", 将数值放入"暂存器"
static code unsigned char DS18B20_CONVERT_T = 0x44;
//功能指令: 从"暂存器"读取温度时
static code unsigned char DS18B20_READ_SCRATCHPAD = 0xBE;

/**
 * 温度变换：初始化→跳过ROM →开始温度变换
 * 温度分辨率配置:
 * R1  R0  转换位数     最大转换时间
 * 0   0   9         93.75ms  t_CONV / 8
 * 0   1   10        187.5ms  t_CONV / 4
 * 1   0   11        375ms    t_CONV / 2
 * 1   1   12        750ms    t_CONV        
 * 
 * *转换12位时, 最大转换时间750ms. 如果第1次就要获取正确的温度, 在调用本方法后delay750ms, 示例:
 *  DS18B20_Convert_T();
 *  Delayms(750);
 *  DS18B20_Convert_T();
 *  float temperature = DS18B20_ReadT();
 */
void DS18B20_Convert_T() {
    if(_1WIRE_Init()) return;
    _1WIRE_sendByte(DS18B20_SKIP_ROM);
    _1WIRE_sendByte(DS18B20_CONVERT_T);
}

/**
 * 温度读取：初始化→跳过ROM →读暂存器→连续的读操作
 * 先读取低位LSB, 再读取高位MSB, ∵温度由2个字节组成
 * 
 * 温度存储格式
 * 2³ 2² 2¹ 2º  2-¹  2-²  2-³  2-⁴    LSB
 * S  S  S  S   S    2⁶   2⁵   2⁴     MSB   //S: 温度≥0,前5位S=0.   温度<0,前5位S=1
 * 
 * 5397: = 0001 0101 0001 0101 = 
 *         0000 0101 0001 0101 = 2^6 + 2^4 + 1 + 0.25 + 0.0625 = 64 + 16 + 1 + 0.3125 = 81.3125
 * 16:     0000 0001 0001 0011
 * 
 * 
 * TEMPERATURE    DIGITAL OUTPUT(Binary)    DIGITAL OUTPUT(Hex)
 * +125°C       0000 0111 1101 0000         07D0h
 * +85°C        0000 0101 0101 0000         0550h*
 * +25.0625°C   0000 0001 1001 0001         0191h
 * +10.125°C    0000 0000 1010 0010         00A2h
 * +0.5°C       0000 0000 0000 1000         0008h
 * 0°C          0000 0000 0000 0000         0000h
 * -0.5°C       1111 1111 1111 1000         FFF8h
 * -10.125°C    1111 1111 0101 1110         FF5Eh
 * -25.0625°C   1111 1110 0110 1111         FF6Fh
 * -55°C        1111 1100 1001 0000         FC90h
 * 
 * *The power on reset register value is +85°C.
 * @return 测温范围：-55°C 到 +125°C, 最高分辨率: 0.0625°C
 */
float DS18B20_ReadT() {
    static unsigned char LSB, MSB;
    static int Temp;           //16位
    if(_1WIRE_Init()) return -273.15F;
    _1WIRE_sendByte(DS18B20_SKIP_ROM);
    _1WIRE_sendByte(DS18B20_READ_SCRATCHPAD);
    LSB = _1WIRE_receiveByte();
    MSB = _1WIRE_receiveByte();
    //将高8位和低8位拼接成1个有符号的int
    Temp = (MSB << 8) | LSB;
    //由于最低位是2-⁴, 所以为了得到真实的值, 需要/16.0F
    return Temp / 16.0F;
}
